package com.quectel.business.dms.application.access.accessor.ieg;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.quectel.business.common.websocket.WebSocketComponent;
import com.quectel.business.common.websocket.send.SendMsgType;
import com.quectel.business.dms.DubboServiceExportFactory;
import com.quectel.business.dms.application.access.AbstractApplicationAccessor;
import com.quectel.business.dms.application.access.accessor.ieg.model.DeviceFaceSendCmd;
import com.quectel.business.dms.application.access.accessor.ieg.model.DeviceQrCodeGenCmd;
import com.quectel.constant.core.eventrecord.PersonAccessRecordConstants;
import com.quectel.constant.core.household.HouseholdConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.core.module.entranceguard.dto.mongo.MongoPersonAccessRecordDto;
import com.quectel.core.module.entranceguard.service.mongo.MongoPersonAccessRecordService;
import com.quectel.core.module.household.dto.HouseholdDto;
import com.quectel.core.module.household.service.HouseholdService;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.spring.SpringUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * 智慧门禁提供的相关能力
 *
 * @author caolu
 * @email louis.cao@quectel.com
 */
public abstract class AbstractIntelligentEntranceGuardAccessor
        extends AbstractApplicationAccessor {

    /**
     * 门禁类设备能力枚举
     */
    public enum AbilityEnum {
        // 开门
        OPEN_DOOR,
        // 人员授权
        AUTH_PERSON;
    }

    /**
     * 能力支持查询(默认全部支持)
     * 子类根据具体类型重写该方法
     *
     * @return
     */
    public abstract List<AbstractIntelligentEntranceGuardAccessor.AbilityEnum> abilities();

    /**
     * 批量开门
     *
     * @param doors 需要开门的设备
     * @return 本次开门是否成功
     */
    public abstract boolean openDoor(List<DeviceDto> doors);

    /**
     * 人员授权 需要支持访客
     *
     * @param deviceInfo
     */
    public abstract void authPerson(DeviceFaceSendCmd deviceInfo);


    /**
     * 生成访客二维码
     *
     * @param deviceQrCodeGenCmd
     * @return
     */
    public abstract String genQrCode(DeviceQrCodeGenCmd deviceQrCodeGenCmd);

    /**
     * 保存进出记录
     *
     * @param personAccessRecord
     * @return
     */
    public void accessRecordHand(MongoPersonAccessRecordDto personAccessRecord) {
        DubboServiceExportFactory factory = SpringUtils.getBean(DubboServiceExportFactory.class);

        final Date currentDate = new Date();
        personAccessRecord.setAccessTime(currentDate);

        // 刷新人员居家状态
        HouseholdService householdService = factory.getHouseholdService();
        HouseholdDto householdDto = householdService.selectById(personAccessRecord.getPersonId());
        if (householdDto != null) {
            Byte isAtHome = HouseholdConstants.IsAtHomeEnum.NOT_AT_HOME.getIsAtHome();
            if (personAccessRecord.getVillageId().equals(householdDto.getVillageId())) {
                // 本小区活动
                if (personAccessRecord.getOutOrIn() == null
                        || PersonAccessRecordConstants.InOrOutEnum.UNKNOWN.getInOrOut().equals(personAccessRecord.getOutOrIn())) {
                    isAtHome = HouseholdConstants.IsAtHomeEnum.UNKNOWN.getIsAtHome();
                } else if (PersonAccessRecordConstants.InOrOutEnum.IN.getInOrOut().equals(personAccessRecord.getOutOrIn())) {
                    isAtHome = HouseholdConstants.IsAtHomeEnum.AT_HOME.getIsAtHome();
                }
            }

            if (!isAtHome.equals(householdDto.getIsAtHome())) {
                // 状态变更了，需要更新
                HouseholdDto newlyDto = new HouseholdDto();
                newlyDto.setId(householdDto.getId());
                newlyDto.setIsAtHome(isAtHome);
                householdService.updateById(newlyDto);
            }

            if (StringUtils.isNotBlank(householdDto.getTags()) && JSONUtil.isTypeJSONObject(householdDto.getTags())) {
                HashMap<String, Object> parse = JacksonUtils.parse(householdDto.getTags(), new TypeReference<HashMap<String, Object>>(){});
                if (parse != null && parse.size() > 0) {
                    personAccessRecord.setFocus(SystemConstants.YES);

                    SpringUtils.getBean(WebSocketComponent.class).sendMsgToCmsApi(householdDto.getVillageId()
                            , SendMsgType.FOCUS.getMsgTypeFlag()
                            , SendMsgType.FOCUS.getTitle()
                            , SendMsgType.FOCUS.getContentFunc().apply(new String[]{householdDto.getName(), DateUtil.now(), personAccessRecord.getDeviceName()})
                            , null);
                }
            }
        }

        // 更新住户出入时间
        Byte outOrIn = personAccessRecord.getOutOrIn();
        if (householdDto != null && outOrIn != null) {
            HouseholdConstants.HouseHoldExtraAttr extraAttr = StringUtils.isNoneBlank(householdDto.getExtraAttr())
                    ? JacksonUtils.parse(householdDto.getExtraAttr(), HouseholdConstants.HouseHoldExtraAttr.class)
                    : new HouseholdConstants.HouseHoldExtraAttr();

            Date accessTime = personAccessRecord.getAccessTime(); // 时间

            if (PersonAccessRecordConstants.InOrOutEnum.IN.getInOrOut().equals(outOrIn)) {
                extraAttr.setInOrOut(PersonAccessRecordConstants.InOrOutEnum.IN.getInOrOut());
            } else if (PersonAccessRecordConstants.InOrOutEnum.OUT.getInOrOut().equals(outOrIn)) {
                extraAttr.setInOrOut(PersonAccessRecordConstants.InOrOutEnum.OUT.getInOrOut());
            } else {
                extraAttr.setInOrOut(PersonAccessRecordConstants.InOrOutEnum.UNKNOWN.getInOrOut());
            }
            extraAttr.setSnapImages(personAccessRecord.getSnapImages());
            extraAttr.setEventTime(accessTime);

            HouseholdDto updateDto = new HouseholdDto();
            updateDto.setId(householdDto.getId());
            updateDto.setExtraAttr(JacksonUtils.toJsonString(extraAttr));
            householdService.updateById(updateDto);
        }


        // 保存人员进出记录
        MongoPersonAccessRecordService personAccessRecordService = factory.getPersonAccessRecordService();
        personAccessRecordService.save(personAccessRecord);

    }
}
